#ifndef __M_HOST_H__
#define __M_HOST_H__

#include "exchange.hpp"
#include "queue.hpp"
#include "binding.hpp"
#include "message.hpp"

namespace mmq
{

    class VirtualHost
    {
    public:
        using ptr = std::shared_ptr<VirtualHost>;
    public:
        VirtualHost(const std::string &hostname, const std::string &basedir, const std::string &dbfile) :
        _hostname(hostname),
        _emp(std::make_shared<ExchangeManager>(dbfile)), 
        _mqmp(std::make_shared<MsgQueueManager>(dbfile)),
        _bmp(std::make_shared<BindingManager>(dbfile)),
        _mmp(std::make_shared<MessageManager>(basedir))
        {
            QueueMap queues = _mqmp->AllQueue();
            for(auto &queue : queues)
            {
                _mmp->InitQueueMessage(queue.first);
            }
        }

        bool DeclareExchange(const std::string &name, mmq::ExchangeType type, bool durable,
                bool auto_delete, const google::protobuf::Map<std::string, std::string> &args)
        {
            return _emp->DeclareExchange(name, type, durable, auto_delete, args);
        }
        void DeleteExchange(const std::string &name)
        {
            // 删除交换机时，还需要将交换机相关的绑定信息也删除
            _bmp->RemoveExchangeBindings(name);
            _emp->DeleteExchange(name);
        }
        bool ExistExchange(const std::string &name)
        {
            return _emp->Exists(name);
        }
        Exchange::ptr SelectExchange(const std::string &name)
        {
            return _emp->SelectExchange(name);
        }

        bool DeclareQueue(const std::string &name, bool durable, bool exclusive, bool auto_delete, 
            const google::protobuf::Map<std::string, std::string> &args)
        {
            // 要初始化队列的消息句柄(在消息的存储管理中)，以及队列的创建
            _mmp->InitQueueMessage(name);
            return _mqmp->DeclareQueue(name, durable, exclusive, auto_delete, args);
        }
        void DeleteQueue(const std::string &name)
        {
            // 要删除队列消息句柄，队列的绑定信息，以及队列本身
            _mmp->DestroyQueueMessage(name);
            _bmp->RemoveMsgQueueBindings(name);
            _mqmp->DeleteQueue(name);
        }
        bool ExistQueue(const std::string &name)
        {
            return _mqmp->Exists(name);
        }
        QueueMap AllQueues()
        {
            return _mqmp->AllQueue();
        }

        bool Bind(const std::string &ename, const std::string &qname, const std::string &key)
        {
            // 先判断交换机和队列是否存在，再根据两者的_durable判断绑定是否需要持久化
            Exchange::ptr ep = _emp->SelectExchange(ename);
            if(ep.get() == nullptr)
            {
                DLOG("进行队列绑定失败，交换机%s不存在！", ename.c_str());
                return false;
            }
            MsgQueue::ptr mqp = _mqmp->SelectQueue(qname);
            if(mqp.get() == nullptr)
            {
                DLOG("进行队列绑定失败，队列%s不存在！", qname.c_str());
                return false;
            }
            return _bmp->Bind(ename, qname, key, ep->_durable && mqp->_durable);
        }
        void UnBind(const std::string &ename, const std::string &qname)
        {
            _bmp->UnBind(ename, qname);
        }
        MsgQueueBindingMap ExchangeBindings(const std::string &ename)
        {
            return _bmp->GetExchangeBindings(ename);
        }
        bool ExistsBind(const std::string &ename, const std::string &qname)
        {
            return _bmp->Exists(ename, qname);
        }

        bool BasicPublish(const std::string &qname, BasicProperties *bp, const std::string &body)
        {
            MsgQueue::ptr mqp = _mqmp->SelectQueue(qname);
            if(mqp.get() == nullptr)
            {
                DLOG("发布消息失败，队列%s不存在！", qname.c_str());
                return false;
            }
            return _mmp->Insert(qname, bp, body, mqp->_durable);
        }
        MessagePtr BasicConsume(const std::string &qname)
        {
            return _mmp->Front(qname);
        }
        void BasicAck(const std::string &qname, const std::string &msg_id)
        {
            _mmp->Ack(qname, msg_id);
        }
        
        size_t GetQueueAbleMessageCount(const std::string &qname)
        {
            return _mmp->GetAbleCount(qname);
        }

        void Clear()
        {
            _emp->Clear();
            _mqmp->Clear();
            _bmp->Clear();
            _mmp->Clear();
        }

    private:
        std::string _hostname;
        ExchangeManager::ptr _emp;
        MsgQueueManager::ptr _mqmp;
        BindingManager::ptr _bmp;
        MessageManager::ptr _mmp;
    };

}
#endif